package org.study.es.api.high;

import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.*;
import org.elasticsearch.client.indices.*;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.study.es.api.constant.EsConstants;

import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 参考 https://blog.csdn.net/guanshengg/article/details/126315549
 *
 * @author doveylovey
 * @version v1.0.0
 * @email 1135782208@qq.com
 * @date 2023年06月03日
 */
@Slf4j
public class RestHighLevelClientUtils {
    public static RestHighLevelClient getRestHighLevelClient1() {
        RestClientBuilder restClientBuilder = RestClient.builder(new HttpHost(EsConstants.HOST, EsConstants.PORT, "http"))
                .setRequestConfigCallback(requestConfigBuilder -> {
                    requestConfigBuilder.setConnectTimeout(-1);
                    requestConfigBuilder.setSocketTimeout(-1);
                    requestConfigBuilder.setConnectionRequestTimeout(-1);
                    return requestConfigBuilder;
                });
        RestHighLevelClient restHighLevelClient = new RestHighLevelClient(restClientBuilder);
        return restHighLevelClient;
    }

    public static RestHighLevelClient getRestHighLevelClient() {
        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(EsConstants.USERNAME, EsConstants.PASSWORD));
        RestClientBuilder restClientBuilder = RestClient.builder(new HttpHost(EsConstants.HOST, EsConstants.PORT, "http"))
                .setRequestConfigCallback(requestConfigBuilder -> {
                    requestConfigBuilder.setConnectTimeout(-1);
                    requestConfigBuilder.setSocketTimeout(-1);
                    requestConfigBuilder.setConnectionRequestTimeout(-1);
                    return requestConfigBuilder;
                })
                .setHttpClientConfigCallback(httpClientConfigCallback -> {
                    httpClientConfigCallback.setDefaultCredentialsProvider(credentialsProvider);
                    return httpClientConfigCallback;
                });
        RestHighLevelClient restHighLevelClient = new RestHighLevelClient(restClientBuilder);
        return restHighLevelClient;
    }

    /**
     * 创建索引
     *
     * @param indexName
     * @return boolean
     */
    public static boolean createIndex(String indexName) throws IOException {
        try (RestHighLevelClient client = getRestHighLevelClient()) {
            // 创建CreateIndexRequest对象，准备创建一个名为indexName的索引
            CreateIndexRequest request = new CreateIndexRequest(indexName);
            // 设置CreateIndexRequest参数
            /*request.settings(Settings.builder()
                    // 设置分区数
                    .put("index.number_of_shards", 3)
                    // 设置副本数
                    .put("index.number_of_replicas", 2)
            );*/
            // 通过JSON字符串的方式，设置ES索引结构的mapping。注意：通常都是通过json配置文件加载索引mapping配置，不需要拼接字符串
            /*request.mapping("{\n" +
                            "  \"properties\": {\n" +
                            "    \"message\": {\n" +
                            "      \"type\": \"text\"\n" +
                            "    }\n" +
                            "  }\n" +
                            "}",
                    XContentType.JSON);*/
            // 执行请求，创建索引
            CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
            boolean acknowledged = response.isAcknowledged();
            log.info("创建索引：{}，结果：{}", indexName, acknowledged);
            return acknowledged;
        }
    }

    /**
     * 判断索引是否存在
     *
     * @param indexName
     * @return boolean
     */
    public static boolean existsIndex(String indexName) throws IOException {
        try (RestHighLevelClient client = getRestHighLevelClient()) {
            GetIndexRequest request = new GetIndexRequest(indexName);
            boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
            log.info("判断索引：{}是否存在，结果：{}", indexName, exists);
            return exists;
        }
    }

    /**
     * 删除索引
     *
     * @param indexName
     * @return org.elasticsearch.action.delete.DeleteResponse
     */
    public static boolean deleteIndex(String indexName) throws IOException {
        try (RestHighLevelClient client = getRestHighLevelClient()) {
            DeleteIndexRequest request = new DeleteIndexRequest(indexName);
            AcknowledgedResponse response = client.indices().delete(request, RequestOptions.DEFAULT);
            boolean acknowledged = response.isAcknowledged();
            log.info("删除索引：{}，结果：{}", indexName, acknowledged);
            return acknowledged;
        }
    }

    /**
     * 查询索引信息
     *
     * @param indexName
     * @return org.elasticsearch.action.get.GetResponse
     */
    public static Map<String, Object> getIndex(String indexName) throws IOException {
        try (RestHighLevelClient client = getRestHighLevelClient()) {
            GetIndexRequest request = new GetIndexRequest(indexName);
            GetIndexResponse response = client.indices().get(request, RequestOptions.DEFAULT);
            Map<String, Object> map = new LinkedHashMap<>(5) {{
                this.put("indices", response.getIndices());
                this.put("defaultSettings", response.getDefaultSettings());
                this.put("settings", response.getSettings());
                this.put("mappings", response.getMappings());
                this.put("aliases", response.getAliases());
            }};
            log.info("查询索引：{}信息，结果：{}", indexName, map);
            return map;
        }
    }

    /**
     * 查询索引信息(批量)
     *
     * @param indexNameArray
     * @return org.elasticsearch.client.indices.GetIndexResponse
     */
    public static GetIndexResponse getAllIndex(String[] indexNameArray) throws IOException {
        try (RestHighLevelClient client = getRestHighLevelClient()) {
            GetIndexRequest request = new GetIndexRequest(indexNameArray);
            GetIndexResponse response = client.indices().get(request, RequestOptions.DEFAULT);
            String[] indexNames = response.getIndices();
            log.info("查询所有索引信息结果：{}", indexNames);
            // 遍历所有索引和类型，查询数据
            for (String indexName : indexNames) {
                SearchRequest searchRequest = new SearchRequest(indexName);
                SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
                searchSourceBuilder.query(QueryBuilders.matchAllQuery());
                searchRequest.source(searchSourceBuilder);
                SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
                SearchHits hits = searchResponse.getHits();
                log.info("索引：{}，包含{}条数据：", indexName, hits.getTotalHits().value);
                for (SearchHit hit : hits) {
                    log.info("===>{}", hit.getSourceAsString());
                }
            }
            return response;
        }
    }
}
